﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using NHibernate;
using NHibernate.Dialect.Function;
using NHibernate.Linq;
using NHibernate.Type;

namespace BAT.APT.NHDao.Main
{
    public class BaseDao
    {
        //初始化工厂，之后改为注入
        private readonly ISessionFactory _factory;
        public BaseDao()
        {
            _factory = SessionFactory.GetCurrentFactory();
        }


        public static void SetParameterValue(IQuery query, ParameterCondition filterCondition)
        {
            var type = filterCondition.ParamType;
            if (Equals(type, NHibernateUtil.Int32))
            {
                query.SetInt32(filterCondition.ParamName, (int)filterCondition.ParamValue);
            }
            else if (Equals(type, NHibernateUtil.Int64))
            {
                query.SetInt64(filterCondition.ParamName, (long)filterCondition.ParamValue);
            }
            else if (Equals(type, NHibernateUtil.Double))
            {
                query.SetString(filterCondition.ParamName, (string)filterCondition.ParamValue);
            }
            else if (Equals(type, NHibernateUtil.DateTime))
            {
                query.SetDateTime(filterCondition.ParamName, (DateTime)filterCondition.ParamValue);
            }
            else if (Equals(type, NHibernateUtil.String))
            {
                query.SetString(filterCondition.ParamName, (string)filterCondition.ParamValue);
            }
            else if (Equals(type, NHibernateUtil.Boolean))
            {
                query.SetBoolean(filterCondition.ParamName, (bool)filterCondition.ParamValue);
            }
            else if (Equals(type, NHibernateUtil.Object))
            {
                query.SetParameterList(filterCondition.ParamName, (IEnumerable)filterCondition.ParamValue);
            }
            else
            {
                throw new Exception(
                    string.Format(
                        "unrecognized param type {0} for {1}", filterCondition.ParamType, filterCondition.ParamName));
            }
        }


        #region NHDao
        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="T">新增实体类型</typeparam>
        /// <param name="entity">实体</param>
        /// <returns>成功返回新增实体Id，失败返回-1。</returns>
        public int Save<T>(T entity)
        {
            using (ISession session = _factory.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    try
                    {
                        var newId = (int)(session.Save(entity));
                        transaction.Commit();
                        return newId;

                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
            }          
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <typeparam name="T">删除实体类型</typeparam>
        /// <param name="entity">删除实体对象</param>
        public void Delete<T>(T entity)
        {
            using (ISession session = _factory.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    try
                    {
                        session.Delete(entity);
                        transaction.Commit();
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                    }
                }
            }   
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <typeparam name="T">修改实体类型</typeparam>
        /// <param name="entity">修改的实体</param>
        public void Update<T>(T entity)
        {
            using (ISession session = _factory.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    try
                    {
                        session.Update(entity);
                        transaction.Commit();
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                    }
                }
            }   
        }

        /// <summary>
        /// 查询单条数据
        /// </summary>
        /// <typeparam name="T">查询实体类型</typeparam>
        /// <typeparam name="TPk">参数Id类型</typeparam>
        /// <param name="id">参数Id</param>
        /// <returns></returns>
        public T Get<T,TPk>(TPk id)
        {
            ISession session = _factory.OpenSession();
            var entity = session.Get<T>(id);
            session.Flush();
            session.Close();
            return entity;
        }

        /// <summary>
        /// 加载单条数据
        /// </summary>
        /// <typeparam name="T">查询实体类型</typeparam>
        /// <typeparam name="TPk">参数Id类型</typeparam>
        /// <param name="id">参数Id</param>
        /// <returns></returns>
        public T Load<T, TPk>(TPk id)
        {
            ISession session = _factory.OpenSession();
            var entity = session.Load<T>(id);
            session.Flush();
            session.Close();
            return entity;
        }

        /// <summary>
        /// 返回全部数据（无参数）
        /// </summary>
        /// <typeparam name="T">查询类型</typeparam>
        /// <returns></returns>
        public virtual IList<T> QueryAll<T>()
        {
            ISession session = _factory.OpenSession();
            var list = session.Query<T>();
            session.Flush();
            session.Close();
            return list.ToList();
        }

        public virtual IList<T> QueryAll<T>(string hql, IList<ParameterCondition> @params)
        {
            if (@params == null)
            {
                //如果是空返回所有
                return null;
            }

            var includingParamList = @params.Any(p => Equals(p.ParamType, NHibernateUtil.Object));
            if (!includingParamList)
            {   
                //return base.FindAll<T>(hql, @params);
                return null;
            }

            using (ISession session = _factory.OpenSession())
            {
                try
                {
                    var query = session.CreateQuery(hql);

                    foreach (var param in @params)
                    {
                        SetParameterValue(query, param);
                    }

                    return query.List<T>();
                }
                catch (Exception)
                {
                    throw;
                }
                finally
                {
                    //因为有了using所以不需要单独释放
                }
            }

        }

        //public void BatchSave<T>(IList<T> entityList);
        //public void Delete<T, TPk>(params TPk[] ids);
        //public void Delete(string hql, IList<FilterCondition> @params);
        //public virtual T Find<T>(string hql, IList<FilterCondition> @params);
        //public virtual Page<T> FindAll<T>(Page<T> page, string hql, IList<FilterCondition> @params) where T : class;
        //public virtual long QueryCount(string hql, IList<FilterCondition> @params);
        //public virtual void SetParamValue(IQuery query, FilterCondition filterCondition);
        //public void Update(string hql, IList<FilterCondition> @params);
        #endregion



        #region ADODao
        /// <summary>
        /// 执行ExecuteNonQuery
        /// </summary>
        /// <param name="sql">sql</param>
        public void ExecuteNonQuery(string sql)
        {
            ISession session = _factory.OpenSession();
            ITransaction transaction = null;
            try
            {
                transaction = session.BeginTransaction();
                IDbCommand command = session.Connection.CreateCommand();
                transaction.Enlist(command);
                command.CommandText = sql;
                command.ExecuteNonQuery();
                transaction.Commit();
            }
            catch (Exception ex)
            {
                if (transaction != null)
                {
                    transaction.Rollback();
                }
                throw ex;
            }
            finally
            {
                if (session != null)
                {
                    session.Close();
                }
            }
        }
        #endregion
    }



    public class ParameterCondition
    {
        //public FilterCondition(string paramsName, object paramsValue, IType paramsType);
        
        public string ParamName { get; set; }
        public IType ParamType { get; set; }
        public object ParamValue { get; set; }
    }

    

}